import type { Router } from 'vue-router';
import type { LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { $t } from '@/locales';
import { getRoutePath } from '@/router/elegant/transform';

/**
 * Get all tabs
 *
 * @param tabs Tabs
 * @param homeTab Home tab
 */
export function getAllTabs(tabs: App.Global.Tab[], homeTab?: App.Global.Tab) {
    if (!homeTab) {
        console.log('homeTab: ', homeTab);
        return [];
    }

    const filterHomeTabs = tabs.filter((tab) => tab.id !== homeTab.id);

    const fixedTabs = filterHomeTabs
        .filter(isFixedTab)
        .sort((a, b) => a.fixedIndex! - b.fixedIndex!);

    const remainTabs = filterHomeTabs.filter((tab) => !isFixedTab(tab));

    const allTabs = [homeTab, ...fixedTabs, ...remainTabs];

    return updateTabsLabel(allTabs);
}

/**
 * Is fixed tab
 *
 * @param tab
 */
function isFixedTab(tab: App.Global.Tab) {
    return tab.fixedIndex !== undefined && tab.fixedIndex !== null;
}

/**
 * Get tab id by route
 *
 * @param route
 */
export function getTabIdByRoute(route: App.Global.TabRoute) {
    const { path, query = {}, meta } = route;

    let id = path;

    if (meta.multiTab) {
        const queryKeys = Object.keys(query).sort();
        const qs = queryKeys.map((key) => `${key}=${query[key]}`).join('&');

        id = `${path}?${qs}`;
    }

    return id;
}

/**
 * Get tab by route
 *
 * @param route
 */
export function getTabByRoute(route: App.Global.TabRoute) {
    const { name, path, fullPath = path, meta } = route;

    const { title, i18nKey, fixedIndexInTab } = meta;

    // Get icon and localIcon from getRouteIcons function
    const { icon, localIcon } = getRouteIcons(route);

    const label = i18nKey ? $t(i18nKey) : title;

    const tab: App.Global.Tab = {
        id: getTabIdByRoute(route),
        label,
        routeKey: name as LastLevelRouteKey,
        routePath: path as RouteMap[LastLevelRouteKey],
        fullPath,
        fixedIndex: fixedIndexInTab,
        icon,
        localIcon,
        i18nKey
    };

    return tab;
}

/**
 * The vue router will automatically merge the meta of all matched items, and the icons here may be affected by other
 * matching items, so they need to be processed separately
 *
 * @param route
 */
export function getRouteIcons(route: App.Global.TabRoute) {
    // Set default value for icon at the beginning
    let icon: string = route?.meta?.icon || import.meta.env.VITE_MENU_ICON;
    let localIcon: string | undefined = route?.meta?.localIcon;

    // Route.matched only appears when there are multiple matches,so check if route.matched exists
    if (route.matched) {
        // Find the meta of the current route from matched
        const currentRoute = route.matched.find((r) => r.name === route.name);
        // If icon exists in currentRoute.meta, it will overwrite the default value
        icon = currentRoute?.meta?.icon || icon;
        localIcon = currentRoute?.meta?.localIcon;
    }

    return { icon, localIcon };
}

/**
 * Get default home tab
 *
 * @param router
 * @param homeRouteName routeHome in useRouteStore
 */
export function getDefaultHomeTab(router: Router, homeRouteName: LastLevelRouteKey) {
    const homeRoutePath = getRoutePath(homeRouteName);
    const i18nLabel = $t(`route.${homeRouteName}`);

    let homeTab: App.Global.Tab = {
        id: getRoutePath(homeRouteName),
        label: i18nLabel || homeRouteName,
        routeKey: homeRouteName,
        routePath: homeRoutePath,
        fullPath: homeRoutePath
    };

    const routes = router.getRoutes();
    const homeRoute = routes.find((route) => route.name === homeRouteName);
    if (homeRoute) {
        homeTab = getTabByRoute(homeRoute);
    }

    return homeTab;
}

/**
 * Is tab in tabs
 *
 * @param tab
 * @param tabs
 */
export function isTabInTabs(tabId: string, tabs: App.Global.Tab[]) {
    return tabs.some((tab) => tab.id === tabId);
}

/**
 * Filter tabs by id
 *
 * @param tabId
 * @param tabs
 */
export function filterTabsById(tabId: string, tabs: App.Global.Tab[]) {
    return tabs.filter((tab) => tab.id !== tabId);
}

/**
 * Filter tabs by ids
 *
 * @param tabIds
 * @param tabs
 */
export function filterTabsByIds(tabIds: string[], tabs: App.Global.Tab[]) {
    return tabs.filter((tab) => !tabIds.includes(tab.id));
}

/**
 * extract tabs by all routes
 *
 * @param router
 * @param tabs
 */
export function extractTabsByAllRoutes(router: Router, tabs: App.Global.Tab[]) {
    const routes = router.getRoutes();

    const routeNames = routes.map((route) => route.name);

    return tabs.filter((tab) => routeNames.includes(tab.routeKey));
}

/**
 * Get fixed tabs
 *
 * @param tabs
 */
export function getFixedTabs(tabs: App.Global.Tab[]) {
    return tabs.filter(isFixedTab);
}

/**
 * Get fixed tab ids
 *
 * @param tabs
 */
export function getFixedTabIds(tabs: App.Global.Tab[]) {
    const fixedTabs = getFixedTabs(tabs);

    return fixedTabs.map((tab) => tab.id);
}

/**
 * Update tabs label
 *
 * @param tabs
 */
function updateTabsLabel(tabs: App.Global.Tab[]) {
    const updated = tabs.map((tab) => ({
        ...tab,
        label: tab.newLabel || tab.oldLabel || tab.label
    }));

    return updated;
}

/**
 * Update tab by i18n key
 *
 * @param tab
 */
export function updateTabByI18nKey(tab: App.Global.Tab) {
    const { i18nKey, label } = tab;

    return {
        ...tab,
        label: i18nKey ? $t(i18nKey) : label
    };
}

/**
 * Update tabs by i18n key
 *
 * @param tabs
 */
export function updateTabsByI18nKey(tabs: App.Global.Tab[]) {
    return tabs.map((tab) => updateTabByI18nKey(tab));
}

/**
 * find tab by route name
 *
 * @param name
 * @param tabs
 */
export function findTabByRouteName(name: RouteKey, tabs: App.Global.Tab[]) {
    const routePath = getRoutePath(name);

    const tabId = routePath;
    const multiTabId = `${routePath}?`;

    return tabs.find((tab) => tab.id === tabId || tab.id.startsWith(multiTabId));
}
